<?php

/**
 * Rm_Proxy: a proxy-object pattern implementation
 *
 * @author vbolshov
 */

namespace km;

use \Km;

class Proxy {
	/**
	 * the wrapee
	 * @var object
	 */
	private $object;
	/**
	 * the wrapee class
	 * @var string
	 */
	private $class;
	/**
	 * @var array
	 */
	private $constructor_args;
	/**
	 * setup methods, called right after the wrapee is created
	 * @var array 
	 */
	private $setup = array();
	/**
	 * setup functions, called right after the wrapee is created
	 * @var array 
	 */
	private $setup_funcs = array();
	/**
	 * @var callable
	 */
	private $creator;
	/**
	 * @var array
	 */
	private $creator_args = array();
	
	function __construct($class = null, array $constructor_args = array())
	{
		$this->class = $class;
		$this->constructor_args = $constructor_args;
		$this->creator = array($this, 'createObject');
	}
	/**
	 * Set a custom function that will be responsible for the object creation
	 *
	 * @param callable $callback
	 * @param array $args
	 */
	function setCreator($callback, array $args = array())
	{
		$this->creator = $callback;
		$this->creator_args = $args;
	}
	
	function addSetupMethod($method, array $args = array())
	{
		$this->setup[] = array($method, $args);
	}
	
	function addSetupFunction($callback, array $args = array())
	{
		$this->setup_funcs[] = array($callback, $args);
	}
	
	function __call($method, $args)
	{
		if (null === $this->object)
		{
			$this->object = call_user_func_array($this->creator, $this->creator_args);
			foreach ($this->setup as $spec) {
				call_user_func_array(array($this->object, $spec[0]), $spec[1]);
			}
			foreach ($this->setup_funcs as $spec) {
				call_user_func_array($spec[0], array_merge(array($this->object), $spec[1]));
			}
		}
		
		return call_user_func_array(array($this->object, $method), $args);
	}
	/**
	 * default object creator
	 */
	function createObject()
	{
		return Km::create($this->class, $this->constructor_args);
	}
}
